﻿using System;
using System.Reflection;
using System.Windows.Data;
using System.Windows;

// Human Interface Project/Link
// Copyright © 2010 The Little Software Company
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

namespace Hip {
	public class LinkValueConverter: IMultiValueConverter {

		private MemberInfo _member;
		private MemberInfo _setBack;

		public LinkValueConverter( MemberInfo member, MemberInfo setBack ) {
			_member = member;
			_setBack = setBack;
		}

		delegate object function();

		public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			//foreach ( object value in values ) {
			//   if ( value == DependencyProperty.UnsetValue ) // assume this to mean the dependency is not available
			//      return Binding.DoNothing;
			//}
			switch ( _member.MemberType ) {
				case MemberTypes.Property:
					try {
						return ( (PropertyInfo)_member ).GetValue( parameter, BindingFlags.GetProperty, null, null, null );
						//var method = (Func<object>)Delegate.CreateDelegate( typeof( Func<object> ), parameter, ( (PropertyInfo)_member ).GetGetMethod() );
						//return method();
					} catch ( Exception e ) {
						return Binding.DoNothing;
					}
				case MemberTypes.Method:
					try {
						return ( (MethodInfo)_member ).Invoke( parameter, BindingFlags.InvokeMethod, null, null, null );
						//var method = (Func<object>)Delegate.CreateDelegate( typeof( Func<object> ), parameter, (MethodInfo)_member );
						//return method();
					} catch ( Exception e ) {
						return Binding.DoNothing;
					}
				default:
					throw new Exception( "Unsupported member type." );
			}
		}

		public object[] ConvertBack( object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture ) {
			//return new object[] { };//temp
			if ( _setBack != null ) {
				switch ( _setBack.MemberType ) {
					case MemberTypes.Property:
						try {
							( (PropertyInfo)_setBack ).SetValue( parameter, value, BindingFlags.SetProperty, null, null, null );
							return new object[] { };
						} catch ( Exception e ) {
							return null;
						}
					case MemberTypes.Method:
						try {
							// implement an explicit optional reverse (set) method "void Method( object )"
							( (MethodInfo)_setBack ).Invoke( parameter, new object[] { value } );
							return new object[] { };
						} catch ( Exception e ) {
							return null;
						}
					default:
						throw new Exception( "Unsupported member type." );
				}
			} else if ( _member.MemberType == MemberTypes.Property ) {
				try {
					( (PropertyInfo)_member ).SetValue( parameter, value, BindingFlags.SetProperty, null, null, null );
					return new object[] { };
				} catch ( Exception e ) {
					return null;
				}
			} else
				throw new Exception( "SetBack must be provided for two-way bound methods. SetBack methods must currently accept a single 'object' parameter." );
		}
	}
}
